package com.topc.oj.runnable.code;



import com.topc.oj.enums.CodeStatusEnum;
import com.topc.oj.result.CodeRunResult;
import com.topc.oj.runnable.time.TimeRunnable;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Callable;

public class CodeRunnable implements Callable<CodeRunResult> {

    private final ProcessBuilder process;

    private final String input;

    private final int memoryLimit;

    private final int timeLimit;

    public CodeRunnable(ProcessBuilder process, String input, int memoryLimit, int timeLimit) {
        this.process = process;
        this.input = input;
        this.memoryLimit = memoryLimit;
        this.timeLimit = timeLimit;
    }

    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    @Override
    public CodeRunResult call() throws Exception {
        //开始执行代码cmd的进程
        Process p = process.start();
        //传入参数
        try (OutputStream os = p.getOutputStream()) {
            os.write(input.getBytes());
        } catch (IOException e) {
            return new CodeRunResult().setCodeStatusEnum(CodeStatusEnum.UN_KNOW);
        }
        //做时间限制
        new Thread(new TimeRunnable(timeLimit,p)).start();

        //返回对象
        CodeRunResult codeRunResult = new CodeRunResult();
        //捕获输出数据
        try (InputStream is = p.getInputStream()) {
            byte[] buffer = new byte[1024];
            int length;
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            while ((length = is.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                if (outputStream.size() > memoryLimit * 1024 * 1024) {
                    return codeRunResult.setCodeStatusEnum(CodeStatusEnum.MLE);
                }
            }
            codeRunResult.setCodeStatusEnum(CodeStatusEnum.Finish).setContentInfo(outputStream.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return codeRunResult;
    }
}
